using System;
using System.Collections.Generic;
using T.FAS.Runtime.Action.Engine;
using T.FAS.Runtime.Action.SPI;
using T.FAS.Runtime.Base.Common;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity;
using T.ServiceComponent.Kernel.Service;
using ActionType = T.FAS.Runtime.Action.SPI.ActionType;

namespace T.FAS.Runtime.Action.Service
{
    public class ActionExecuteService
    {
        private static ActionExecuteService instance = null;
        private static readonly object lockobj = new object();
        private ActionExecuteService()
        {

        }
        public static ActionExecuteService GetInstance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockobj)
                    {
                        if (instance == null)
                        {
                            instance = new ActionExecuteService();
                        }
                    }
                }

                return instance;
            }
        }

        public TResult Execute(string metaDataID, ActionType actionType, List<ActionParameter> parameters, bool isMatchMetadataByCode =false, RemoteInvokeContext remoteInovkeContext =null)
        {
            var startTime = DateTime.Now;
            Exception ex = null;
            ActionExecContext context = null;
            FASContextHelper.GetInstance().InitRpcContext();
            var reportRpcID = RpcContext.Current.RpcID;
            try
            {
                if (string.IsNullOrEmpty(metaDataID))
                {

/* Unmerged change from project 'T.FAS.Runtime.Action.Service (net451)'
Before:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, CommonStringClass.ActionExecuteService_Execute);
After:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, Service.ActionExecuteService_Execute);
*/
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, CommonStringClassDonotTranslated.ActionExecuteService_Execute);
                }

                context = ActionExecuteContextBuilder.Build(metaDataID, actionType, parameters, isMatchMetadataByCode);

                if (remoteInovkeContext != null)
                    context.RemoteInvokeContext = remoteInovkeContext;

                var engine = ActionExecuteEngineProvider.CreateTransistEngine(context);

                var result = engine.Execute(context);

                return result;

            }
            catch (Exception e)
            {
                ex = e;
                ActionServiceMonitor.RootCaseReport(startTime, context, ex);
                throw e;
            }
            finally
            {
                ActionServiceMonitor.Trace(startTime, context, reportRpcID, ex) ;
                ActionServiceMonitor.MonitorActionServiceInvokeTotalTPS(context);
                if (ex == null)
                {
                    ActionServiceMonitor.MonitorActionServiceInvokeSuccessTPS(context);
                    ActionServiceMonitor.MonitorActionServiceInvokeSuccessDuration(context,(DateTime.Now - startTime).TotalMilliseconds);
                }
                else
                {
                    ActionServiceMonitor.MonitorActionServiceInvokeFailTPS(context);
                }
            }
        }

        public TResult Execute(string metaDataId, string actionCode, List<ActionParameter> parameters, bool isMatchMetadataByCode = false)
        {
            var startTime = DateTime.Now;
            Exception ex = null;
            ActionExecContext context = null;
            FASContextHelper.GetInstance().InitRpcContext();
            var reportRpcId = RpcContext.Current.RpcID;
            try
            {
                if (string.IsNullOrEmpty(metaDataId))
                {

/* Unmerged change from project 'T.FAS.Runtime.Action.Service (net451)'
Before:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, CommonStringClass.ActionExecuteService_Execute1);
After:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, Service.CommonStringClassDonotTranslated.ActionExecuteService_Execute1);
*/
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, CommonStringClassDonotTranslated.ActionExecuteService_Execute1);
                }
                if (string.IsNullOrEmpty(actionCode))
                {

/* Unmerged change from project 'T.FAS.Runtime.Action.Service (net451)'
Before:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, CommonStringClass.ActionExecuteService_Execute2);
After:
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, Service.CommonStringClassDonotTranslated.ActionExecuteService_Execute2);
*/
                    throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, CommonStringClassDonotTranslated.ActionExecuteService_Execute2);
                }

                context = ActionExecuteContextBuilder.Build(metaDataId, actionCode, parameters, isMatchMetadataByCode);

                var engine = ActionExecuteEngineProvider.CreateTransistEngine(context);

                return engine.Execute(context);

            }
            catch (Exception e)
            {
                ex = e;
                ActionServiceMonitor.RootCaseReport(startTime, context, ex);
                throw e;
            }
            finally
            {
                ActionServiceMonitor.Trace(startTime, context, reportRpcId, ex);
                ActionServiceMonitor.MonitorActionServiceInvokeTotalTPS(context);
                if (ex == null)
                {
                    ActionServiceMonitor.MonitorActionServiceInvokeSuccessTPS(context);
                    ActionServiceMonitor.MonitorActionServiceInvokeSuccessDuration(context, (DateTime.Now - startTime).TotalMilliseconds);
                }
                else
                {
                    ActionServiceMonitor.MonitorActionServiceInvokeFailTPS(context);
                }
            }
        }
    }
}
